﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using JXT.PrimaryKey.Batman.Collections;
using JXT.PrimaryKey.Batman.Domain.Services;
using JXT.PrimaryKey.Batman.Domain.Specifications;
using JXT.PrimaryKey.Batman.Domain.VirtualExchange.Models;
using JXT.PrimaryKey.Batman.Domain.VirtualExchange.Repositories;
using JXT.PrimaryKey.Batman.Domain.Quotation.Models;
using JXT.PrimaryKey.Batman.Domain.Repositories;

namespace JXT.PrimaryKey.Batman.Domain.VirtualExchange.Services.Default
{
    public class SecuritiesDetailService : CachedServiceBase<SecuritiesDetail>, ISecuritiesDetailService
    {
        private static readonly int _defaultWaitTime = 20;

        #region ISecuritiesDetailService Members

        public void Add(SecuritiesDetail entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
            if (entity.Id > 0)
                throw new ArgumentException("entity.Id must be 0.");
            LoadRepository<ISecuritiesDetailRepository>().Add(entity);
        }

        public void AddList(IEnumerable<SecuritiesDetail> list, Action<TaskExecutedStatus> updateAction = null)
        {
            if (list == null)
                throw new ArgumentNullException("list");
            RepositoryContext.BeginTransaction();
            try
            {
                int total = list.Count();
                int finished = 0;
                int skip = 0;
                double rate = 0;
                foreach (var item in list)
                {
                    LoadRepository<ISecuritiesDetailRepository>().Add(item);
                    UpdateProcess(total, ref finished, ref skip, ref rate, false, updateAction);
                    Thread.Sleep(_defaultWaitTime);
                }
                RepositoryContext.CommitTransaction();
            }
            catch
            {
                RepositoryContext.RollbackTransaction();
                throw;
            }
            finally
            {
                RepositoryContext.DisposeTransaction();
            }
        }

        public void Delete(SecuritiesDetail entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
            if (entity.Id <= 0)
                throw new ArgumentNullException("entity.Id must be larger than 0.");
            LoadRepository<ISecuritiesDetailRepository>().Delete(entity.Id);
        }

        public int Count(DateTime time)
        {
            var specification = SpecificationFactory.CreateSpecification<SecuritiesDetail>();
            specification.And(e => e.UpdateTime == time);
            return LoadRepository<ISecuritiesDetailRepository>().Count(specification);
        }

        public SecuritiesDetail GetSingle(int id)
        {
            var specification = SpecificationFactory.CreateSpecification<SecuritiesDetail>();
            specification.And(e => e.Id == id);
            return GetSingle(specification);
        }

        public SecuritiesDetail GetSingle(ISpecification<SecuritiesDetail> specification)
        {
            if (specification == null)
                throw new ArgumentNullException("specification");
            var find = LoadRepository<ISecuritiesDetailRepository>().GetSingle(specification);
            return find;
        }

        public IPagedCollection<SecuritiesDetail> GetList(IPagedSpecification<SecuritiesDetail> specification)
        {
            if (specification == null)
                throw new ArgumentNullException("specification");
            var list = LoadRepository<ISecuritiesDetailRepository>().GetList(specification);
            return list;
        }

        public IEnumerable<SecuritiesDetail> GetListByHoldingCount(int pageSize, int pageIndex, SecuritiesType securitiesType, MarketType marketType = MarketType.Hongkong)
        {
            if (securitiesType == SecuritiesType.Unknown)
                throw new ArgumentException("securitiesType参数不能为unknown");
            if (marketType == MarketType.Unknown)
                throw new ArgumentException("markettype参数不能为unknown");
            if (pageSize <= 0)
                pageSize = 10;
            if (pageIndex <= 0)
                pageIndex = 1;
            IEnumerable<SecuritiesDetail> list = new List<SecuritiesDetail>();
            var lastDateTime = LoadRepository<ISecuritiesDetailRepository>().GetLastDateTime();
            if (lastDateTime == null)
                return list;
            var pagedSpecification = SpecificationFactory.CreatePagedSpecification<SecuritiesDetail>();
            pagedSpecification.IsEnablePaged = true;
            pagedSpecification.PageIndex = pageIndex;
            pagedSpecification.PageSize = pageSize;
            pagedSpecification.And(e => e.SecuritiesType == securitiesType && e.MarketType == marketType && e.UpdateTime == lastDateTime.Value);
            pagedSpecification.OrderBy(e => e.HoldingCount, OrderType.Descending);
            list=LoadRepository<ISecuritiesDetailRepository>().GetListByHoldingCount(pagedSpecification);
            return list;
        }

        public IEnumerable<SecuritiesDetail> GetListByHoldingAccountCount(int pageSize, int pageIndex, Quotation.Models.SecuritiesType securitiesType, Quotation.Models.MarketType marketType = MarketType.Hongkong)
        {
            if (securitiesType == SecuritiesType.Unknown)
                throw new ArgumentException("securitiesType参数不能为unknown");
            if (marketType == MarketType.Unknown)
                throw new ArgumentException("markettype参数不能为unknown");
            if (pageSize <= 0)
                pageSize = 10;
            if (pageIndex <= 0)
                pageIndex = 1;
            IEnumerable<SecuritiesDetail> list = new List<SecuritiesDetail>();
            var lastDateTime = LoadRepository<ISecuritiesDetailRepository>().GetLastDateTime();
            if (lastDateTime == null)
                return list;
            var pagedSpecification = SpecificationFactory.CreatePagedSpecification<SecuritiesDetail>();
            pagedSpecification.IsEnablePaged = true;
            pagedSpecification.PageIndex = pageIndex;
            pagedSpecification.PageSize = pageSize;
            pagedSpecification.And(e => e.SecuritiesType == securitiesType && e.MarketType == marketType && e.UpdateTime == lastDateTime.Value);
            pagedSpecification.OrderBy(e => e.HoldAccountCount, OrderType.Descending);
            list=LoadRepository<ISecuritiesDetailRepository>().GetListByHoldingAccountCount(pagedSpecification);
            return list;
        }

        #endregion

        #region override method
        public override RepositoryContext RepositoryContext
        {
            get
            {
                return LoadRepository<ISecuritiesDetailRepository>().Context;
            }
        }
        #endregion

        private void UpdateProcess(int total, ref int finished, ref int skip, ref double rate, bool isSkip, Action<TaskExecutedStatus> updateAction)
        {
            finished++;
            if (isSkip)
                skip++;
            double newRate = (double)finished / (double)total * 100;
            if ((newRate - rate >= 0.5 || finished == total) && updateAction != null)
            {
                try
                {
                    updateAction(new TaskExecutedStatus() { Finished = finished, Total = total, Skip = skip });
                }
                catch { }
                rate = newRate;
            }
        }
    }
}
